package com.navinfo.gateway.platform.server.netty.handler;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 服务分发
 *
 * @author zhengshibo
 * @date 2018/3/14.
 */
@Component
@ChannelHandler.Sharable
public class TerminalDispatchTcpHandler extends ChannelInboundHandlerAdapter {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(TerminalDispatchTcpHandler.class);

    /**
     * 先打开连接
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelRegistered();
        logger.info("channelRegistered {}", ctx.channel().remoteAddress().toString());
    }

    /**
     * 客户端连接后，再触发此方法
     *
     * @param ctx
     * @throws Exception
     */
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelActive();
        logger.info("channelActive {}", ctx.channel().remoteAddress().toString());
    }

    /**
     * 客户端主动断开连接
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //todo
        //根据业务场景，需要编写一下代码
        //1，删除设备和链路关系
        //2.通知业务侧设备掉线
        //todo
        ctx.fireChannelInactive();
        logger.info("channelInactive{}", ctx.channel().remoteAddress().toString());
    }

    /**
     * 客户端异常,断开连接后，再触发此方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        //todo
        //根据业务场景，需要编写一下代码
        //1，删除设备和链路关系
        //2.通知业务侧设备掉线
        //todo
        ctx.fireExceptionCaught(cause);
        logger.info("[exceptionCaught] 终端异常断开连接,[{}],{}", ctx.channel().remoteAddress().toString(), cause.getMessage());
    }

    /**
     * 心跳设置
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            //todo
            //根据业务场景，需要编写一下代码
            //1.判断心跳类型
            //2.根据心跳判断是否是非法设备,或者设备再次重连
            //todo
            if (event.state().equals(IdleState.READER_IDLE)) {
                ctx.close();
            }
        }
        super.userEventTriggered(ctx, evt);
    }

    /**
     * 服务端收到客户端发送过来的消息时，触发此方法，根据command派发指定handler
     *
     * @param channelHandlerContext
     * @param o
     * @throws Exception
     */
    public void channelRead(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        try {
            //todo
            //根据业务场景，需要编写一下代码
            //1.首先根据协议去解码
            //2.设备首次连接一般需要。判断注册鉴权
            //3.如果注册鉴权成功，需要保存设备和链路的关系。如果注册鉴权失败，需要返回失败code
            //4.根据不同的协议去分发对应的处理类
            //todo
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

}
